package com.spring.nio.core.event.handler;

import com.google.common.collect.Lists;
import com.spring.nio.core.channel.context.SocketChannelContext;
import com.spring.nio.core.event.business.StickyHalfBagParseUtil;
import com.spring.nio.core.event.listener.event.constant.ExceptionEventTypeEnum;
import com.spring.nio.core.event.listener.event.model.ExceptionEventSource;
import com.spring.nio.core.event.listener.event.model.NioReadExceptionEventSource;
import com.spring.nio.core.event.model.*;
import com.spring.nio.core.exception.ExceptionManager;
import com.spring.nio.core.pool.WorkerThreadPool;
import com.spring.nio.util.BasicUtil;
import com.spring.nio.util.LocalTime;
import com.spring.nio.util.NioUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @Auther: YSFY
 * @Date: 2020-11-21 12:07
 * @Pacage_name: com.spring.nio.core.event.handler
 * @Project_Name: net-server
 * @Description: 读事件处理[ReadEventHandler]
 *  事件模型对象关系转化
 *
 *                                                  selector.select()
 *                                                          |
 *                                                          |
 *       ChannelCacheDataModel                         EventModel                               PackageData
 *
 *        1、selector.select()方法监听socketChannel通道可选事件，处理ReadEvent
 *        2、将ReadEvent中SelectionKey健中的数据封装为EventModel
 *        3、获取当前ReadEvent中所对应通道的缓存数据对象ChannelCacheDataModel
 *        4、执行拆包半包处理，将能够完成处理的帧数据追加到eventModel completeList中,将不能够按照完整帧处理的数据添加至ChannelCacheDataModel list中
 *        5、将能够执行业务处里的数据封装进PackageData中执行业务处理
 *
 *        --> 所以每一个ReadEvent事件对应的socketChannel的数据在执行拆包半包处理时都不会存在线程安全问题，因为Selector线程是单线程循环处理,那么经过拆包
 *          半包处理后能够进行业务处理的数据都是有序的且完整的，此时可以封装为FileUploadTask任务提交线程池进行
 *
 */
@Slf4j
@SuppressWarnings("all")
public class ReadEventHandler extends AbstractEventHandler {
    private static Integer chatIndex = 0;

    @Override
    public EventModel eventHandler(EventModel eventModel) {
        if(!super.checkEventValid(eventModel)) {
            return eventModel;
        }

        if(!eventModel.getSelectionKey().isReadable()) {
            if(!Optional.ofNullable(super.getNextEventHandler()).isPresent()) {
                return eventModel;
            }
            return super.getNextEventHandler().eventHandler(eventModel);
        }

        return this.read(eventModel);
    }

    /**
     * 执行处理,提交线程池处理读事件,解决粘包半包问题后，提交数据至线程池处理
     * @param eventModel
     * @return eventModel
     * */
    private EventModel read(EventModel eventModel) {
        // 粘包和半包处理成功，则开启异步数据处理
        if(StickyHalfBagParseUtil.parse(eventModel, this.getCurrentChannelCacheModel(eventModel), eventModel.getRemoteAddress())) {
            SocketChannelContext socketChannelContext = (SocketChannelContext) eventModel.getSelectionKey().attachment();
            List<FrameData> fullFrameDataList = eventModel.getFullFrameDataList();
            WorkerThreadPool.submit(PacketData.newPacket(socketChannelContext, fullFrameDataList), eventModel.getEventModelEnum());
        }
        return eventModel;
    }


}
